#include "Aquarium_Modes.h";

#include "Aquarium_Devices.h";
#include "Water_Level.h";

extern Aquarium_Devices aquarium_devices;
extern Water_Level      water_level;
extern Clock            clock;

extern LiquidCrystal lcd;

prog_char mode_name_0[] PROGMEM = "Normal";
prog_char mode_name_1[] PROGMEM = "Feeding Fish";
prog_char mode_name_2[] PROGMEM = "Feeding 1";
prog_char mode_name_3[] PROGMEM = "Feeding 2";
prog_char mode_name_4[] PROGMEM = "Water C Empty";
prog_char mode_name_5[] PROGMEM = "Water C Fill";
prog_char mode_name_6[] PROGMEM = "Water C mix";
prog_char mode_name_7[] PROGMEM = "Elc Blackout";

PROGMEM const char *modes_name_table[] = 
{   
  mode_name_0,
  mode_name_1,
  mode_name_2,
  mode_name_3,
  mode_name_4,
  mode_name_5,
  mode_name_6,
  mode_name_7
};


prog_char Float_Mode_name_0[] PROGMEM = "Not Active";
prog_char Float_Mode_name_1[] PROGMEM = "when On";
prog_char Float_Mode_name_2[] PROGMEM = "when Off";

PROGMEM const char *Float_Mode_name_table[] = 
{   
  Float_Mode_name_0,
  Float_Mode_name_1,
  Float_Mode_name_2
};



Aquarium_Modes::Aquarium_Modes()  : 
Curr_Aquarium_mode(0) ,
Timer(0),
mode_change(0){
  init();
};

void Aquarium_Modes::init(){

  for (int i = 0 ; i  < NUMBER_OF_MODES ; ++i){
    int address = EEPROM_MODES_ADDRESS_START + (EEPROM_MODES_ADDRESS_OFFSET *i);
    MoveTo[i] = EEPROM.read(address++);
    MoveToAfter[i] = EEPROM.read(address++);
    for (int j = 0 ; j  < MODES_NUMBER_OF_TIMERS ; ++j){   
      Timer_On[ i ] [ j ] = EEPROM.read(address++);
      Timer_HR[ i ][ j ] = EEPROM.read(address++);
      Timer_MIN[ i ][ j] = EEPROM.read(address++);
      Timer_DAY[ i ][ j] = EEPROM.read(address++);
      Timer_MoveTo[ i ][ j ] = EEPROM.read(address++);
    }
     for (int j = 0 ; j  < WATER_LEVEL_NUMBER_OF_FLOATS ; ++j){   
      Floats_Mode[ i ][ j ] = (Float_Mode) EEPROM.read(address++);
      Float_MoveTo[ i ][ j ] =  EEPROM.read(address++);
    }
  }

}

void Aquarium_Modes::Save_To_EEPROM(){
  for (int i = 0 ; i  < NUMBER_OF_MODES ; ++i){
    int address = EEPROM_MODES_ADDRESS_START + (EEPROM_MODES_ADDRESS_OFFSET *i);
    EEPROM.write(address++, MoveTo[i]) ;
    EEPROM.write(address++, MoveToAfter[i]) ;
    for (int j = 0 ; j  < MODES_NUMBER_OF_TIMERS ; ++j){   
      EEPROM.write(address++, Timer_On[ i ] [ j ] );
      EEPROM.write(address++, Timer_HR[ i ][ j ] );
      EEPROM.write(address++, Timer_MIN[ i ][ j] );
      EEPROM.write(address++, Timer_DAY[ i ][ j] );
      EEPROM.write(address++, Timer_MoveTo[ i ][ j ] );
    }
    for (int j = 0 ; j  < WATER_LEVEL_NUMBER_OF_FLOATS ; ++j){   
      EEPROM.write(address++, (byte)Floats_Mode[ i ][ j ] );
      EEPROM.write(address++, Float_MoveTo[ i ][ j ] ); 
    }
  }
}

void Aquarium_Modes::MoveToMode( byte ModeNum ){
  Curr_Aquarium_mode = ModeNum;
  Timer = MoveToAfter[ModeNum];
  mode_change = true;
  water_level.update();
  delay(250);
  aquarium_devices.update_devices();
  delay(250);
   lcd.begin(LCD_COLUMNS, LCD_LINES);
}

void Aquarium_Modes::update(){
  byte Cur_Hr = clock.get_hr();
  byte Cur_Min = clock.get_min();
   byte Cur_Day = clock.get_day();

  if ( Timer > 1){
    --Timer;
  }
  else if ( Timer == 1){
    MoveToMode(MoveTo[Curr_Aquarium_mode]);
  }

  for (int i = 0 ; i  < MODES_NUMBER_OF_TIMERS ; ++i){   
    if (    Timer_On[ Curr_Aquarium_mode ] [ i ] &&
      (Timer_HR[ Curr_Aquarium_mode ][ i ] ==  Cur_Hr) &&
      (Timer_MIN[ Curr_Aquarium_mode ][ i] == Cur_Min)  &&
      (bitRead(Timer_DAY[ Curr_Aquarium_mode ][ i] , Cur_Day ) )    ){
      MoveToMode(Timer_MoveTo[ Curr_Aquarium_mode ][ i ]);
    }
  }

}

void Aquarium_Modes::update_sec(){ 
  for (int i = 0 ; i  < WATER_LEVEL_NUMBER_OF_FLOATS ; ++i){   
    if (    Floats_Mode[ Curr_Aquarium_mode ][ i ] == eWHEN_ON &&
            water_level.Get_Float_Status(i)  ){
      MoveToMode(Float_MoveTo[ Curr_Aquarium_mode ][ i ]);
    }
    if (    Floats_Mode[ Curr_Aquarium_mode ][ i ] == eWHEN_OFF && 
            !water_level.Get_Float_Status(i) ){
      MoveToMode(Float_MoveTo[ Curr_Aquarium_mode ][ i ]);
    }    
  }
}




void Aquarium_Modes::SetMoveTo(byte ModeNum, byte Mode){ 
  MoveTo[ModeNum] = Mode;
}
byte Aquarium_Modes::GetMoveTo(byte ModeNum){ 
  return MoveTo[ModeNum];
}
void Aquarium_Modes::SetMoveToAfter(byte ModeNum, byte Time){ 
  MoveToAfter[ModeNum] =Time;
}
byte Aquarium_Modes::GetMoveToAfter(byte ModeNum){ 
  return MoveToAfter[ModeNum];
}

void Aquarium_Modes::SetTimer_On(byte ModeNum, byte Timer ,bool On){ 
  Timer_On[ModeNum] [ Timer ] = On;
}
bool Aquarium_Modes::GetTimer_On(byte ModeNum, byte Timer){ 
  return Timer_On[ModeNum][Timer];
}

void Aquarium_Modes::SetTimer_HR(byte ModeNum, byte Timer ,byte HR ){ 
  Timer_HR[ModeNum] [ Timer ] = HR;
}
byte Aquarium_Modes::GetTimer_HR(byte ModeNum, byte Timer){ 
  return Timer_HR[ModeNum][Timer];
}


void Aquarium_Modes::SetTimer_MIN(byte ModeNum, byte Timer ,byte Min){ 
  Timer_MIN[ModeNum] [ Timer ] = Min;
}
byte Aquarium_Modes::GetTimer_MIN(byte ModeNum, byte Timer){ 
  return Timer_MIN[ModeNum][Timer];
}



void Aquarium_Modes::SetTimer_DAY(byte ModeNum, byte Timer ,byte Day){ 
  Timer_DAY[ModeNum] [ Timer ] = Day;
}
byte Aquarium_Modes::GetTimer_DAY(byte ModeNum, byte Timer){ 
  return Timer_DAY[ModeNum][Timer];
}


void Aquarium_Modes::SetTimer_MoveTo(byte ModeNum, byte Timer ,byte MoveTo){ 
  Timer_MoveTo[ModeNum] [ Timer ] = MoveTo;
}
byte Aquarium_Modes::GetTimer_MoveTo(byte ModeNum, byte Timer){ 
  return Timer_MoveTo[ModeNum][Timer];
}

void Aquarium_Modes::SetFloat_Mode(byte ModeNum,byte Float_Num,Float_Mode Float_Mode){
  Floats_Mode[ModeNum][Float_Num] = Float_Mode;
}
Float_Mode Aquarium_Modes::GetFloat_Mode(byte ModeNum,byte Float_Num){
  return Floats_Mode[ModeNum][Float_Num];
}
  

void Aquarium_Modes::SetFloat_MoveTo(byte ModeNum,byte Float_Num,byte inFloat_MoveTo){
  Float_MoveTo[ModeNum][Float_Num] = inFloat_MoveTo;
}
byte Aquarium_Modes::GetFloat_MoveTo(byte ModeNum,byte Float_Num){
  return Float_MoveTo[ModeNum][Float_Num];
}


void Aquarium_Modes::Print_Float_Status(Float_Mode Float_Mode){
  switch(Float_Mode){
    case eNOT_ACTIVE:
      strcpy_P(buffer, (char*)pgm_read_word(&(  Float_Mode_name_table[ 0 ]     )));
    break;
    case eWHEN_ON:
     strcpy_P(buffer, (char*)pgm_read_word(&(  Float_Mode_name_table[ 1 ]     )));
    break;
    case eWHEN_OFF:
     strcpy_P(buffer, (char*)pgm_read_word(&(  Float_Mode_name_table[ 2 ]     )));
    break;
  }
  lcd.print(buffer );
}
Float_Mode Aquarium_Modes::DecFloats_Mode(Float_Mode Float_Mode){
   switch(Float_Mode){
    case eNOT_ACTIVE:
       return eNOT_ACTIVE;
    break;
    case eWHEN_ON:
       return eNOT_ACTIVE;
    break;
    case eWHEN_OFF:
     return eWHEN_ON;
    break;
  }
}
Float_Mode Aquarium_Modes::IncFloats_Mode(Float_Mode Float_Mode){
  switch(Float_Mode){
    case eNOT_ACTIVE:
      return eWHEN_ON;
    break;
    case eWHEN_ON:
     return eWHEN_OFF;
    break;
    case eWHEN_OFF:
      return eWHEN_OFF;
    break;
  }
}
  
  
void  Aquarium_Modes::Print(byte Mode_num){
  strcpy_P(buffer, (char*)pgm_read_word(&(  modes_name_table[ Mode_num ]     )));
  lcd.print(buffer );
}

void  Aquarium_Modes::Print(){

  strcpy_P(buffer, (char*)pgm_read_word(&(  modes_name_table[ Curr_Aquarium_mode]     )));
  lcd.print(buffer );
}












